#ifndef __H_MVP_TRANSPORT_H__
#define __H_MVP_TRANSPORT_H__

#include "common/macros.h"
#include "transport/common/transport_api.h"
#include "transport/receiver/receiver.h"

#ifdef DEF_BUILD_LCM
#include "transport/receiver/lcm_receiver.h"
#include "transport/transmitter/lcm_transmitter.h"
#endif
#ifdef DEF_BUILD_SHM
#include "transport/receiver/shm_receiver.h"
#include "transport/transmitter/shm_transmitter.h"
#endif
#ifdef DEF_BUILD_PPS
#include "transport/receiver/pps_receiver.h"
#include "transport/transmitter/pps_transmitter.h"
#endif

#include "transport/transmitter/transmitter.h"
#include "transport/receiver/dds_receiver.h"
#include "transport/transmitter/dds_transmitter.h"

namespace motovis {
namespace transport {

class Transport {
  public:
    virtual ~Transport();

    template <typename MessageT>
    auto createTransmitter(const std::string &transmitter_conf,
                           const transport::TransportModel &model)
        -> std::shared_ptr<Transmitter<MessageT>>;

    template <typename MessageT>
    auto createReceiver(const std::string &receiver_conf,
                        const TransportModel &model)
        -> std::shared_ptr<Receiver<MessageT>>;

  private:
    DECLARE_SINGLETON(Transport)
};

template <typename MessageT>
auto Transport::createTransmitter(const std::string &transmitter_conf,
                                  const TransportModel &model)
    -> std::shared_ptr<Transmitter<MessageT>>
{
    std::shared_ptr<Transmitter<MessageT>> transmitter = nullptr;

    switch(model) {
#ifdef DEF_BUILD_LCM
        case TransportModel::LCM:
            transmitter = std::make_shared<LcmTransmitter<MessageT>>();
            break;
#endif
#ifdef DEF_BUILD_PPS
        case TransportModel::PPS:
            transmitter = std::make_shared<PpsTransmitter<MessageT>>();
            break;
#endif
#ifdef DEF_BUILD_SHM
        case TransportModel::SHM:
            transmitter = std::make_shared<ShmTransmitter<MessageT>>();
            break;
#endif
        case TransportModel::DDS:
        default:
            transmitter = std::make_shared<DDSTransmitter<MessageT>>();
            break;
    }
    
    return transmitter;
}
    
template <typename MessageT>
auto Transport::createReceiver(const std::string &receiver_conf,
                               const transport::TransportModel &model)
    -> std::shared_ptr<Receiver<MessageT>>
{
    std::shared_ptr<Receiver<MessageT>> receiver = nullptr; 

    switch(model) {
#ifdef DEF_BUILD_LCM
        case TransportModel::LCM:
            receiver = std::make_shared<LcmReceiver<MessageT>>();
            break;
#endif
#ifdef DEF_BUILD_PPS
        case TransportModel::PPS:
            receiver = std::make_shared<PpsReceiver<MessageT>>();
            break;
#endif
#ifdef DEF_BUILD_SHM
        case TransportModel::SHM:
            receiver = std::make_shared<ShmReceiver<MessageT>>();
            break;
#endif
        case TransportModel::DDS:
        default:
            receiver = std::make_shared<DDSReceiver<MessageT>>();
            break;
    }
    
    return receiver;
}

} // namespace transport
} // namespace motovis

#endif //__H_MVP_TRANSPORT_H__